package com.li.collision
{

import away3dlite.arcane;

import flash.geom.Vector3D;

use namespace arcane;

/*
 Mathematical plane in 3D space with no visual representation.
 */
public class MathematicalPlane
{
    public static const FRONT:int = 1;
    public static const BACK:int = -1;
    public static const INTERSECT:int = 0;

    /**
     * The A coefficient of this plane. (Also the x dimension of the plane normal)
     */
    public var a:Number;

    /**
     * The B coefficient of this plane. (Also the y dimension of the plane normal)
     */
    public var b:Number;

    /**
     * The C coefficient of this plane. (Also the z dimension of the plane normal)
     */
    public var c:Number;

    /**
     * The D coefficient of this plane. (Also the inverse dot product between normal and point)
     */
    public var d:Number;

    // indicates the alignment of the normal
    arcane static const ANY:int = 0;
    arcane static const X_AXIS:int = 1;
    arcane static const Y_AXIS:int = 2;
    arcane static const Z_AXIS:int = 3;

    //arbitrary point on this plane, only avail during closest computation
    private var _point:Vector3D = new Vector3D();

    public function MathematicalPlane(a:Number = 0, b:Number = 0, c:Number = 0, d:Number = 0)
    {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
    }

    public function defineFrom3points(p0:Vector3D, p1:Vector3D, p2:Vector3D):void
    {
        var d1x:Number = p1.x - p0.x;
        var d1y:Number = p1.y - p0.y;
        var d1z:Number = p1.z - p0.z;

        var d2x:Number = p2.x - p0.x;
        var d2y:Number = p2.y - p0.y;
        var d2z:Number = p2.z - p0.z;

        a = d1y*d2z - d1z*d2y;
        b = d1z*d2x - d1x*d2z;
        c = d1x*d2y - d1y*d2x;
        d = - (a*p0.x + b*p0.y + c*p0.z);
    }

    public function defineFromNormalAndPoint(normal:Vector3D, point:Vector3D):void
    {
        a = normal.x;
        b = normal.y;
        c = normal.z;
        d = -(a*point.x + b*point.y + c*point.z);

        _point = normal;
    }

    public function classifyPoint(p:Vector3D):int
    {
        // check NaN
        if(!(d <= 0 || d > 0))
            return MathematicalPlane.FRONT;

        var len:Number = a*p.x + b*p.y + c*p.z + d;

        if(len < 0)
            return MathematicalPlane.BACK;
        else if(len > 0)
            return MathematicalPlane.FRONT;
        else
            return MathematicalPlane.INTERSECT;
    }

    public function toString():String
    {
        return "MathematicalPlane [a:" + a + ", b:" + b + ", c:" + c + ", d:" + d + "].";
    }
}
}
